package com.xjc.infra.interceptor;


import java.lang.reflect.Method;

import javax.jms.TextMessage;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.activemq.command.ActiveMQTextMessage;
import org.springframework.beans.factory.annotation.Autowired;

import com.xjc.infra.base.BaseErrorCodes;
import com.xjc.infra.entity.BaseErrorCode;
import com.xjc.infra.entity.ExecuteState;
import com.xjc.infra.entity.SessionContext;
import com.xjc.infra.entity.service.TransactionStatus;
import com.xjc.infra.entity.service.XGenericReponseDTO;
import com.xjc.infra.entity.service.XGenericRequestDTO;
import com.xjc.infra.exception.IFSException;
import com.xjc.infra.util.InfraUtil;
import com.xjc.infra.util.JsonUtil;
import com.xjc.infra.util.LoggerUtil;
import com.xjc.infra.util.ReferenceNoUtils;
import com.xjc.infra.util.SessionContextUtil;
import com.xjc.infra.util.SystemGlobals;


/**
 * 日志拦截器
 * @class com.ifs.portal.util.LoggerInterceptor
 *
 * @date 2016年6月16日
 * @author lqf
 *
 */
public class LoggerInterceptor implements MethodInterceptor {
	@Autowired
	private LoggerUtil loggerUtil;
	
	private Long startMillis;
	
	@Autowired
	private SessionContextUtil sessionContextUtil;  

	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
		Object ret = null;
		try{
			startMillis = System.currentTimeMillis();
		    changeSession(methodInvocation);
        	initLog(methodInvocation);
        	ret = methodInvocation.proceed();
		 }catch(Throwable ex){
			ret = errorLog(methodInvocation, ex, null);
		 }finally{
			 endLog(methodInvocation, startMillis,ret);
		 }
		 return ret;
	}
	
	/**
	 * 改变session 用于跨系统调用时
	 * @param methodInvocation
	 * @date 2016年6月17日
	 * @author lqf
	 */
	private void changeSession(MethodInvocation methodInvocation){
		SessionContext sessionContext =  getSessionContext(methodInvocation);
		
		if(null==sessionContext||sessionContext.getEntityCode()==null){			   
			sessionContext = sessionContextUtil.createSessionContext();
			sessionContextUtil.fillSessionContext(sessionContext);
		}else{
			Integer entityCode = Integer.valueOf(SystemGlobals.getProperty("entityCode"));
			String serviceCode = SystemGlobals.getProperty("serviceCode");
			//跨系统时改变sessionContext属性值
			if(null== sessionContext.getEntityCode() || entityCode.intValue()!=sessionContext.getEntityCode().intValue()){
				sessionContext.setEntityCode(entityCode);
				sessionContext.setServiceCode(serviceCode);
				sessionContext.setOriginalReferenceNo(sessionContext.getExternalReferenceNo());
				sessionContext.setExternalReferenceNo(ReferenceNoUtils.createSysDefaultReferenceNo());
			}
		}
		SessionContextUtil.setLocalSessionContext(sessionContext); 
		setSessionContext(methodInvocation,sessionContext);
	}

	/**
	 * 请求初始化日志记录
	 * @param methodInvocation
	 * @date 2016年6月16日
	 * @author lqf
	 * @throws Exception 
	 */
	private void initLog(MethodInvocation methodInvocation) throws Exception{
//		loggerUtil.logInit( getRequestDTO(methodInvocation),  getAbsoluteMethodName(methodInvocation));
		loggerUtil.logInit(methodInvocation.getArguments(),  getAbsoluteMethodName(methodInvocation));
	}
	
	/**
	 * 响应日志记录
	 * @param methodInvocation
	 * @param startMillis
	 * @param ret
	 * @date 2016年6月16日
	 * @author lqf
	 */
	private void endLog(MethodInvocation methodInvocation,Long startMillis,Object ret){
		SessionContextUtil.clearLocalSessionContext();
		loggerUtil.logEnd(getResponseObject(ret), getSessionContext(methodInvocation), getAbsoluteMethodName(methodInvocation), startMillis);
	}
	
	/**
	 * 错误日志记录
	 * @param chain
	 * @param ex
	 * @return
	 * @date 2016年6月16日
	 * @author lqf
	 * @throws Throwable 
	 */
	private Object errorLog(MethodInvocation methodInvocation,Throwable ex,Object ret) throws Throwable {
		loggerUtil.logError(methodInvocation.getArguments(),getSessionContext(methodInvocation), getAbsoluteMethodName(methodInvocation), ex);
		
		String absServiceName = methodInvocation.getMethod().getReturnType().getName();
		if("org.springframework.web.servlet.ModelAndView".endsWith(absServiceName)){
			throw ex;
		}
		
		TransactionStatus ts = new TransactionStatus();
		ts.setSuccess(false);
		if(ex instanceof IFSException){
			IFSException e = (IFSException)ex;
			ts.setErrorCode(e.getErrorCode());
			ts.setReplyText(e.getMessage());
		}else{
			ts.setErrorCode(BaseErrorCode.BASE_ERROR);//设置系统错误
			ts.setReplyText("交易异常失败");
		}
		String[] args = methodInvocation.getMethod().toString().split("throws")[0].split(" ");
		String arg1 = args[1];
		if("void".equals(arg1)){
			return ret;
		}
	    Class<?> clazz = Class.forName(args[1]);
	    Object obj = clazz.newInstance();
		if(obj instanceof XGenericReponseDTO){//返回ResponseDTO
			Method m1 = getMethodObj(obj.getClass());
			m1.invoke(obj,ts);
		    return obj;
		}else if(obj instanceof TransactionStatus){//返回TransactionStatus
			return ts;
		}else if(obj instanceof ExecuteState){//返回ExecuteState
			ExecuteState executeState = InfraUtil.transferStatusObj(ts);
			return executeState;
		}else{
			return ret;
		}
	}
	
	/**
	 * 获取XGenericReponseDTO中的setTransactionStatus方法
	 * @author lqf 
	 * @date 2016年12月20日 下午4:24:00
	 * @param clazz
	 * @return
	 * @throws Throwable
	 */
	private Method getMethodObj(Class<?>  clazz) throws Throwable{
		Method m = null;
		if(clazz.getSimpleName().equals("XGenericReponseDTO")){
			m = clazz.getDeclaredMethod("setTransactionStatus",TransactionStatus.class);
			return m;
		}else{
			return getMethodObj(clazz.getSuperclass());
		}
	}
	
	/**
	 * 获取sessionContext
	 * @param methodInvocation
	 * @return
	 * @date 2016年6月27日
	 * @author lqf
	 */
	private SessionContext getSessionContext(MethodInvocation methodInvocation){
		Object[] args = methodInvocation.getArguments();
		if(null==args || args.length==0){
			return null;
		}
		for(Object obj :args){
			if(obj instanceof XGenericRequestDTO){
				return ((XGenericRequestDTO) obj).getSessionContext();
			}
			else if(obj instanceof SessionContext){
				return (SessionContext)obj;
			}
			else if(obj instanceof ActiveMQTextMessage)
			{
				try {
					TextMessage  message =(TextMessage)obj;					
					XGenericRequestDTO req = (XGenericRequestDTO)JsonUtil.fromJson(message.getText(), XGenericRequestDTO.class);	
					return req.getSessionContext();
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				
			}
		}
		return null;
	}
	
	/**
	 * 设置sessionContext
	 * @param methodInvocation
	 * @param sessionContext
	 * @date 2016年6月27日
	 * @author lqf
	 */
	private void setSessionContext(MethodInvocation methodInvocation,SessionContext sessionContext){
		Object[] args = methodInvocation.getArguments();
		Class<?>[] clzzs = methodInvocation.getMethod().getParameterTypes();
		if(null==args || args.length==0){
			return;
		}
		int i=0;
		for(Object obj :args){
			if(obj==null)
			{
				try {
					obj = Class.forName(clzzs[i].getName());
				} catch (Exception e) {
					loggerUtil.logError(methodInvocation.getArguments(),getSessionContext(methodInvocation), getAbsoluteMethodName(methodInvocation), e);
				}
			}
			if(obj instanceof XGenericRequestDTO){
				((XGenericRequestDTO) obj).setSessionContext(sessionContext);
			}
			if(obj instanceof SessionContext){
				args[i] = sessionContext;				
			}
			i++;
		}
	}
	
	/**
	 * 获取响应DTO
	 * @param methodInvocation
	 * @return
	 * @date 2016年6月17日
	 * @author lqf
	 */
	private Object getResponseObject(Object  ret){
		Object responseObj ;
		if(ret instanceof XGenericReponseDTO){//返回ResponseDTO
			responseObj = (XGenericReponseDTO)ret;
		}else if(ret instanceof TransactionStatus){//返回TransactionStatus
			responseObj = (TransactionStatus)ret;
		}else{
			responseObj = ret;
		}
		return responseObj;
	}

	/**
	 * 获取访问接口全限定名称
	 * @param methodInvocation
	 * @return
	 * @date 2016年6月17日
	 * @author lqf
	 */
	private String getAbsoluteMethodName(MethodInvocation methodInvocation){
		String[] args = methodInvocation.getMethod().toString().split("throws")[0].split(" ");
		return args[args.length-1];
	}

	
	public LoggerUtil getLoggerUtil() {
		return loggerUtil;
	}

	public void setLoggerUtil(LoggerUtil loggerUtil) {
		this.loggerUtil = loggerUtil;
	}

//	public HttpServletRequest getRequest() {
//		return request;
//	}
//
//	public void setRequest(HttpServletRequest request) {
//		this.request = request;
//	}

	public SessionContextUtil getSessionContextUtil() {
		return sessionContextUtil;
	}

	public void setSessionContextUtil(SessionContextUtil sessionContextUtil) {
		this.sessionContextUtil = sessionContextUtil;
	}
}
